home *** CD-ROM | disk | FTP | other *** search
/ Nothing but Tetris / Nothing but Tetris.iso / amiga / yactris / src / yactris.c < prev    next >
C/C++ Source or Header  |  1994-01-01  |  25KB  |  1,150 lines

  1. /*
  2.     YacTris v0.0
  3.     Copyright ⌐1993 Jonathan P. Springer
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 1, or (at your option)
  8.     any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     For more details see the files README and COPYING, which should have
  20.     been included in this distribution.
  21.  
  22.     The author can be reached during the school year at these E-Mail addresses:
  23.  
  24.     springjp@screech.alfred.edu        (Internet)
  25.     springjp@ceramics.bitnet        (Bitnet)
  26.  
  27.     And can be reached by paper mail year-round at the following address:
  28.  
  29.     Jonathan Springer
  30.     360 W. Main St.
  31.     Dallastown, PA    17313-2014
  32.     USA
  33.  
  34. */
  35.  
  36.  
  37. /*
  38. **
  39. **  yactris.c
  40. **
  41. **  The definitive Tetris for AmigaDOS 2.0
  42. **
  43. **  Jonathan Springer
  44. **
  45. **  v 0.0
  46. **
  47. */
  48.  
  49. #include <exec/types.h>
  50. #include <exec/memory.h>
  51. #include <exec/ports.h>
  52. #include <dos/dos.h>
  53. #include <graphics/displayinfo.h>
  54. #include <graphics/gfxmacros.h>
  55. #include <intuition/intuition.h>
  56. #include <intuition/screens.h>
  57. #include <libraries/gadtools.h>
  58. #include <utility/tagitem.h>
  59. #include <workbench/startup.h>
  60. #include <stdio.h>
  61. #include <stdlib.h>
  62. #include <string.h>
  63. #include <time.h>
  64. #include <dbug.h>
  65. #include "yactris.h"
  66. #include <bruce.h>
  67.  
  68. /****************/
  69. /*  Prototypes    */
  70. /****************/
  71.  
  72. #include <clib/dos_protos.h>
  73. #include <clib/exec_protos.h>
  74. #include <clib/icon_protos.h>
  75. #include <clib/intuition_protos.h>
  76. #include <clib/graphics_protos.h>
  77. #include <clib/gadtools_protos.h>
  78. #include <clib/layers_protos.h>
  79.  
  80. Prototype void TStartUp(void);
  81. Prototype void Tetris(void);
  82. Prototype struct PieceRot *PickPiece(void);
  83. Prototype void ClearPlayField(void);
  84. Prototype BOOL NewPiece(struct PieceRot *, int, int);
  85. Prototype BOOL MovePiece(enum direction);
  86. Prototype BOOL RotatePiece(void);
  87. Prototype void ByeBye(int);
  88. Prototype void PlacePiece(void);
  89. Prototype BOOL GameOver(void);
  90. Prototype void ResetTet(void);
  91. Prototype void FillInTWindow(struct Window *, struct ScreenInfo *);
  92. Prototype BOOL IsHitting(struct PieceRot *, int, int);
  93. Prototype void DoNewPubScreen(struct Screen *news);
  94. Prototype BOOL VerifyQuit(void);
  95. Prototype int NoBreak(void);
  96.  
  97. enum direction {left, down, right, null};
  98.  
  99. /***********************/
  100. /*  Piece Definitions  */
  101. /***********************/
  102.  
  103. const UBYTE Multi[] =
  104. /*    0  0  0  0  0  0    0  0  0  0  1  1  1  1    1  1  1  1  1  1  2  2
  105.       0  1  2  3  4  5    6  7  8  9  0  1  2  3    4  5  6  7  8  9  0  1      */
  106.  
  107.     { 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1 };
  108.  
  109. extern struct MakeStruct LineM0[], LineM1[], BlockM[], TeeM0[], TeeM1[],
  110.     TeeM2[], TeeM3[], ZigM0[], ZigM1[], ZagM0[], ZagM1[], EllM0[], EllM1[],
  111.     EllM2[], EllM3[], LeeM0[], LeeM1[], LeeM2[], LeeM3[];
  112.  
  113. struct PieceRot Line[2] = {
  114.     { LINE, &Line[1], {0}, 4, 1, &Multi[4], LineM0 },
  115.     { LINE, Line, {0}, 1, 4, &Multi[4], LineM1 }
  116. };
  117.  
  118. struct PieceRot Block = { BLOCK, &Block, {0}, 2, 2, &Multi[4], BlockM };
  119.  
  120. struct PieceRot Tee[4] = {
  121.     { TEE, &Tee[1], {0}, 3, 2, &Multi[9], TeeM0 },
  122.     { TEE, &Tee[2], {0}, 2, 3, &Multi[10], TeeM1 },
  123.     { TEE, &Tee[3], {0}, 3, 2, &Multi[12], TeeM2 },
  124.     { TEE, Tee, {0}, 2, 3, &Multi[11], TeeM3 }
  125. };
  126.  
  127. struct PieceRot Zig[2] = {
  128.     { ZIG, &Zig[1], {0}, 3, 2, Multi, ZigM0 },
  129.     { ZIG, Zig, {0}, 2, 3, &Multi[3], ZigM1 }
  130. };
  131.  
  132. struct PieceRot Zag[2] = {
  133.     { ZAG, &Zag[1], {0}, 3, 2, &Multi[3], ZagM0 },
  134.     { ZAG, Zag, {0}, 2, 3, &Multi[16], ZagM1 }
  135. };
  136.  
  137. struct PieceRot Ell[4] = {
  138.     { ELL, &Ell[1], {0}, 3, 2, &Multi[2], EllM0 },
  139.     { ELL, &Ell[2], {0}, 2, 3, &Multi[14], EllM1 },
  140.     { ELL, &Ell[3], {0}, 3, 2, &Multi[4], EllM2 },
  141.     { ELL, Ell, {0}, 2, 3, &Multi[13], EllM3 }
  142. };
  143.  
  144. struct PieceRot Lee[4] = {
  145.     { LEE, &Lee[1], {0}, 3, 2, &Multi[1], LeeM0 },
  146.     { LEE, &Lee[2], {0}, 2, 3, &Multi[12], LeeM1 },
  147.     { LEE, &Lee[3], {0}, 3, 2, &Multi[5], LeeM2 },
  148.     { LEE, Lee, {0}, 2, 3, &Multi[9], LeeM3 }
  149. };
  150.  
  151. struct BitMap Sqbm = {0};
  152.  
  153. struct PieceRot *Pieces[NUM_TYPES] = { Line, &Block, Tee, Zig, Zag, Ell, Lee };
  154. int PieceCount[NUM_TYPES] = {0};
  155.  
  156. /**********************/
  157. /*  Menu Definitions  */
  158. /**********************/
  159.  
  160. struct NewMenu tNewMenu[] = {
  161.     { NM_TITLE, "Game",          0 ,    0,  0,  0 },
  162.     {  NM_ITEM, "Start",        "S",    0,  0,  0 },
  163.     {  NM_ITEM, "Halt",         "H",    0,  0,  0 },
  164.     {  NM_ITEM, "Reset",        "R",    0,  0,  0 },
  165.     {  NM_ITEM, NM_BARLABEL,     0 ,    0,  0,    0 },
  166.     {  NM_ITEM, "About...",     "?",    0,  0,  0 },
  167.     {  NM_ITEM, NM_BARLABEL,     0 ,    0,  0,    0 },
  168.     {  NM_ITEM, "Quit...",      "Q",    0,  0,  0 },
  169.     { NM_TITLE, "Display",       0 ,    0,  0,  0 },
  170.     {  NM_ITEM, "Show Next",     0 ,    CHECKIT|CHECKED|MENUTOGGLE, 0, 0},
  171.     {  NM_ITEM, "Show Piece Count", 0,   CHECKIT|MENUTOGGLE, 0, 0},
  172.     {  NM_ITEM, NM_BARLABEL,     0 ,    0,  0,    0 },
  173.     {  NM_ITEM, "New Screen...","P",    0,  0,  0 },
  174.     {    NM_END, NULL,         0 ,    0,  0,    0 }
  175. };
  176.  
  177. /***********************/
  178. /*  The Playing Field  */
  179. /***********************/
  180. UBYTE Field[FWIDTH][FHEIGHT] = {0};
  181.  
  182. /***************/
  183. /*  The Piece  */
  184. /***************/
  185. struct PieceRot *Piece=NULL, *Next=NULL;
  186. int Px, Py;
  187.  
  188. /***************/
  189. /*  The Score  */
  190. /***************/
  191.  
  192. int StartLev = 0;
  193. const int CapLev = 11;
  194. int Level;
  195. int Lines = 0;
  196. int Score = 0;
  197. int Lin2Inc = 10;
  198. BOOL ShowNext = TRUE;
  199.  
  200. char *StartScreen = NULL;
  201. char ss[MAXPUBSCREENNAME];
  202.  
  203. /***********************/
  204. /*  System Structures  */
  205. /***********************/
  206.  
  207. struct Window *tWindow = NULL;
  208. struct Window *pWindow = NULL;
  209. struct Screen *tScreen = NULL;
  210. struct Menu *tMenus = NULL;
  211. struct ScreenInfo *ScrInfo = NULL;
  212.  
  213. struct Library *IconBase;
  214.  
  215. int NoBreak(void) { return 0; }
  216.  
  217. /*
  218. **  main()
  219. */
  220.  
  221. int main (int argc, char **argv) {
  222.  
  223.     int i;
  224.  
  225. #ifndef DBUG_OFF
  226. #define ARGS 4
  227.     char template[] = "STARTLEVEL/K/N, LINESTOINC/K/N, PUBSCREEN/K, D=DBUG/K/F";
  228. #else
  229. #define ARGS 3
  230.     char template[] = "STARTLEVEL/K/N, LINESTOINC/K/N, PUBSCREEN/K";
  231. #endif
  232.  
  233.     ULONG argout[ARGS] = {0};
  234.     struct RDArgs *rda = NULL;
  235.  
  236.     DBUG_ENTER("main");
  237.  
  238. #ifdef DBUG_OFF
  239.     onbreak(NoBreak);
  240. #endif
  241.  
  242.     DBUG_PROCESS(argv[0]);
  243.  
  244.     if (rda=ReadArgs(template, argout, NULL)) {
  245.  
  246.     if (argout[0]) StartLev = *( (LONG *) argout[0]);
  247.  
  248.     if (argout[1]) Lin2Inc = *( (LONG *) argout[1]);
  249.  
  250.     if (argout[2]) StartScreen = strcpy(ss, (char *) argout[2]);
  251.  
  252. #ifndef DBUG_OFF
  253.     if (argout[3]) DBUG_PUSH( (char *) argout[2] );
  254. #endif
  255.  
  256.     }
  257.  
  258.     if (rda) FreeArgs(rda);
  259.  
  260.     TStartUp();
  261.  
  262.     exit(0);
  263.  
  264.     DBUG_RETURN(0);
  265. }
  266.  
  267. /*
  268. **  wbmain()
  269. */
  270. int wbmain(struct WBStartup *wbs)
  271. {
  272.     struct DiskObject *dobj = NULL;
  273.     char *tstr;
  274.     BPTR olddir = -1;
  275.  
  276.     DBUG_ENTER("wbmain");
  277.  
  278.     DBUG_PROCESS(wbs->sm_ArgList->wa_Name);
  279.  
  280.     if (IconBase = OpenLibrary("icon.library",33)) {
  281.  
  282.     if (wbs->sm_ArgList->wa_Lock)
  283.         olddir = CurrentDir(wbs->sm_ArgList->wa_Lock);
  284.  
  285.     if (dobj=GetDiskObject(wbs->sm_ArgList->wa_Name)) {
  286.  
  287.         if (tstr = FindToolType(dobj->do_ToolTypes, "STARTLEVEL"))
  288.         StartLev = atoi(tstr);
  289.  
  290.         if (tstr = FindToolType(dobj->do_ToolTypes, "LINESTOINC"))
  291.         Lin2Inc = atoi(tstr);
  292.  
  293.         if (tstr = FindToolType(dobj->do_ToolTypes, "PUBSCREEN"))
  294.         StartScreen = strcpy(ss, tstr);
  295.  
  296. #ifndef DBUG_OFF
  297.         if (tstr = FindToolType(dobj->do_ToolTypes, "DBUG"))
  298.         DBUG_PUSH(tstr);
  299. #endif
  300.  
  301.         FreeDiskObject(dobj);
  302.  
  303.     }
  304.  
  305.     if (olddir != -1) CurrentDir(olddir);
  306.  
  307.     }
  308.  
  309.     TStartUp();
  310.  
  311.     if (IconBase) CloseLibrary(IconBase);
  312.  
  313.     exit(0);
  314.  
  315.     DBUG_RETURN(0);
  316. }
  317.  
  318. /*
  319. **
  320. **  TStartUp()
  321. **
  322. **  Start up and Tetrisize
  323. **
  324. */
  325. void TStartUp(void)
  326. {
  327.     struct Screen *tScreen;
  328.  
  329.     DBUG_ENTER("TStartUp");
  330.  
  331.     srand(time(NULL));
  332.  
  333.     if (!(tScreen = LockPubScreen(StartScreen)))
  334.     tScreen = LockPubScreen(NULL);
  335.  
  336.     if (ScrInfo = CreateScrInfo(tScreen)) {
  337.  
  338.     /*  Construct the Menus  */
  339.     if (tMenus = CreateMenus(tNewMenu, TAG_DONE)) {
  340.  
  341.         if (LayoutMenus(tMenus, ScrInfo->vi, TAG_DONE)) {
  342.  
  343.         /*  Open the Windows  */
  344.         if (tWindow=OpenTWindow(ScrInfo, tMenus)) {
  345.  
  346.             /*    Make the Pieces  */
  347.             if (MakePieces(ScrInfo)) {
  348.  
  349.             ResetTet();
  350.  
  351.             /*  Do the Tetris thing  */
  352.             Tetris();
  353.  
  354.             }
  355.  
  356.             UnMakePieces(ScrInfo);
  357.  
  358.         }
  359.         }
  360.     }
  361.     }
  362.  
  363.     /*    Clean Up  */
  364.     if (pWindow) ClosePWindow(pWindow);
  365.     if (tWindow) CloseTWindow(tWindow);
  366.     if (tMenus) FreeMenus(tMenus);
  367.     if (ScrInfo) {
  368.     if (ScrInfo->s) UnlockPubScreen(NULL, ScrInfo->s);
  369.     FreeScrInfo(ScrInfo);
  370.     }
  371.  
  372.     DBUG_VOID_RETURN;
  373. }
  374.  
  375. /*
  376. **
  377. **  Tetris()
  378. **
  379. **  Do the actual Tetrising
  380. **
  381. */
  382.  
  383. void Tetris(void)
  384. {
  385.     int tickstodrop = CapLev - Level;
  386.     BOOL active = FALSE, hitting = FALSE, over = FALSE;
  387.     BOOL breakmenloop = FALSE;
  388.     int tickcount = 0;
  389.     struct IntuiMessage *inMsg;
  390.     int i;
  391.  
  392.     UWORD Code;
  393.     ULONG Class;
  394.     ULONG signals;
  395.     struct Window *IWindow;
  396.  
  397.     struct Screen *news;
  398.  
  399.     DBUG_ENTER("Tetris");
  400.  
  401.     FlagWindow(tWindow, FALSE);
  402.  
  403.     while (!over) {
  404.     signals = Wait(1L << tWindow->UserPort->mp_SigBit);
  405.     while ((!over) &&
  406.         (inMsg = (struct IntuiMessage *) GetMsg(tWindow->UserPort))
  407.     ) {
  408.         Code = inMsg->Code;
  409.         Class = inMsg->Class;
  410.         IWindow = inMsg->IDCMPWindow;
  411.         ReplyMsg( (struct Message *) inMsg);
  412.         switch(Class) {
  413.  
  414.         case IDCMP_MENUPICK:
  415.         DBUG_PRINT("Tetris",("PickMenu received"));
  416.         breakmenloop = FALSE;
  417.         while (Code != MENUNULL) {
  418.  
  419.         switch (MENUNUM(Code)) {
  420.  
  421.         case 0:
  422.             if (ITEMNUM(Code)!=NOITEM) switch (ITEMNUM(Code)) {
  423.  
  424.             case 0:
  425.             active = TRUE;
  426.             FlagWindow(tWindow, TRUE);
  427.             break;
  428.             case 1:
  429.             active = FALSE;
  430.             FlagWindow(tWindow, FALSE);
  431.             break;
  432.             case 2:
  433.             ResetTet();
  434.             active = FALSE;
  435.             FlagWindow(tWindow, FALSE);
  436.             tickcount = 0;
  437.             tickstodrop = CapLev-Level;
  438.             hitting = FALSE;
  439.             break;
  440.             case 4:
  441.             DoAbout(ScrInfo);
  442.             break;
  443.             case 6:
  444.             if (VerifyQuit()) breakmenloop = over = TRUE;
  445.             break;
  446.             default:
  447.             break;
  448.  
  449.             }
  450.             break;
  451.  
  452.         case 1:
  453.             if (ITEMNUM(Code)!=NOITEM) switch (ITEMNUM(Code)) {
  454.  
  455.             case 0:
  456.             if (ItemAddress(tMenus, Code)->Flags & CHECKED) {
  457.                 if (!ShowNext) ShowNext = TRUE;
  458.                 BltBitMapRastPort(&Next->BitMap, 0, 0,
  459.                 tWindow->RPort,
  460.                 ScrInfo->NPLeft, ScrInfo->NPTop,
  461.                 4*ScrInfo->xTimes, 4*ScrInfo->yTimes, 0xc0);
  462.             } else if (ShowNext) {
  463.                 ShowNext = FALSE;
  464.                 EraseRect(tWindow->RPort,
  465.                 ScrInfo->NPLeft, ScrInfo->NPTop,
  466.                 ScrInfo->NPLeft+4*ScrInfo->xTimes-1,
  467.                 ScrInfo->NPTop+4*ScrInfo->yTimes-1);
  468.             }
  469.             break;
  470.  
  471.             case 1:
  472.             if (ItemAddress(tMenus, Code)->Flags & CHECKED) {
  473.                 if (!pWindow) {
  474.                 if (pWindow =
  475.                     OpenPWindow(ScrInfo, tWindow->UserPort
  476.                 )) {
  477.                     for (i=0; i<NUM_TYPES; i++)
  478.                     DispPCount(ScrInfo, pWindow,
  479.                         Pieces[i], PieceCount[i]);
  480.                 } else {
  481.                     ClearMenuStrip(tWindow);
  482.                     ItemAddress(tMenus, Code)->Flags &=
  483.                         ~CHECKED;
  484.                     ResetMenuStrip(tWindow, tMenus);
  485.                 }
  486.                 }
  487.             } else if (pWindow) {
  488.                 ClosePWindow(pWindow);
  489.                 pWindow = NULL;
  490.             }
  491.             break;
  492.  
  493.             case 3:
  494.             if (news = InquirePubScreen(ScrInfo)) {
  495.                 DBUG_PRINT("Tetris",("Opening new window, Screen Address %p",news));
  496.                 DoNewPubScreen(news);
  497.                 active = FALSE;
  498.                 FlagWindow(tWindow, FALSE);
  499.                 tickcount = 0;
  500.                 BltBitMapRastPort(&Piece->BitMap,0,0,
  501.                 tWindow->RPort,
  502.                 ScrInfo->FieldInLeft + Px * ScrInfo->xTimes,
  503.                 ScrInfo->FieldInTop + Py * ScrInfo->yTimes,
  504.                 Piece->width * ScrInfo->xTimes,
  505.                 Piece->height * ScrInfo->yTimes, 0x60);
  506.                 hitting = IsHitting(Piece, Px, Py);
  507.                 UpdateScores(tWindow, ScrInfo, Level, Score, Lines);
  508.                 breakmenloop = TRUE;
  509.             }
  510.  
  511.             default:
  512.             break;
  513.  
  514.             }
  515.  
  516.         default:
  517.             break;
  518.  
  519.         }
  520.  
  521.         if (breakmenloop) Code = MENUNULL;
  522.         else Code = ItemAddress(tMenus, Code)->NextSelect;
  523.         }
  524.  
  525.         break;
  526.  
  527.         case IDCMP_CLOSEWINDOW:
  528.         DBUG_PRINT("Tetris",("CloseWindow received"));
  529.         if (IWindow == tWindow) {
  530.             over = TRUE;
  531.         } else if (IWindow == pWindow && pWindow) {
  532.             ClosePWindow(pWindow);
  533.             pWindow = NULL;
  534.             ClearMenuStrip(tWindow);
  535.             ItemAddress(tMenus, FULLMENUNUM(1,1,NOSUB))->Flags &=
  536.                 ~CHECKED;
  537.             ResetMenuStrip(tWindow, tMenus);
  538.         }
  539.         break;
  540.  
  541.         case IDCMP_INTUITICKS:
  542.         if (!(tickcount = ++tickcount % tickstodrop)) {
  543.             if (!hitting)
  544.             hitting=MovePiece(down);
  545.             else {
  546.             PlacePiece();
  547.             if (NewPiece(PickPiece(),STARTX,STARTY)) {
  548.                 active=FALSE;
  549.                 if (!( over = GameOver() )) ResetTet();
  550.                 FlagWindow(tWindow, FALSE);
  551.             }
  552.             hitting = FALSE;
  553.             tickcount = 0;
  554.             tickstodrop = CapLev - Level;
  555.             }
  556.         }
  557.         break;
  558.  
  559.         case IDCMP_VANILLAKEY:
  560.         switch (Code) {
  561.  
  562.         case '4':
  563.             hitting=MovePiece(left);
  564.             break;
  565.         case '6':
  566.             hitting=MovePiece(right);
  567.             break;
  568.         case '2':
  569.             if (!hitting)
  570.             hitting=MovePiece(down);
  571.             else {
  572.             PlacePiece();
  573.             if (NewPiece(PickPiece(),STARTX,STARTY)) {
  574.                 active=FALSE;
  575.                 if (!( over = GameOver() )) ResetTet();
  576.                 FlagWindow(tWindow, FALSE);
  577.             }
  578.             hitting = FALSE;
  579.             tickcount = 0;
  580.             tickstodrop = CapLev - Level;
  581.             }
  582.             break;
  583.         case '5':
  584.             hitting=RotatePiece();
  585.             break;
  586.         default:
  587.             break;
  588.         }
  589.         break;
  590.  
  591.         default:
  592.         break;
  593.         }
  594.     }
  595.     }
  596.  
  597.     DBUG_VOID_RETURN;
  598. }
  599.  
  600. /*
  601. **
  602. **  PickPiece()
  603. **
  604. **  Pick a piece to fall next
  605. **
  606. */
  607.  
  608. struct PieceRot *PickPiece(void)
  609. {
  610.     struct PieceRot *p;
  611.  
  612.     DBUG_ENTER("PickPiece");
  613.  
  614.     if (!Next) Next = Pieces[rand()%NUM_TYPES];
  615.  
  616.     p = Next;
  617.     Next = Pieces[rand() % NUM_TYPES];
  618.  
  619.     if (ShowNext) BltBitMapRastPort(&Next->BitMap, 0, 0,tWindow->RPort,
  620.         ScrInfo->NPLeft, ScrInfo->NPTop, 4*ScrInfo->xTimes, 4*ScrInfo->yTimes,
  621.         0xc0);
  622.  
  623.     DBUG_RETURN(p);
  624. }
  625.  
  626. /*
  627. **
  628. **  ClearPlayField()
  629. **
  630. **  Clear the playfield array and clear the window display
  631. **
  632. */
  633.  
  634. void ClearPlayField(void)
  635. {
  636.     int i, j;
  637.  
  638.     DBUG_ENTER("ClearPlayField");
  639.  
  640.     for (i=0; i<FHEIGHT; i++)
  641.     for (j=0; j<FWIDTH; j++)
  642.         Field[j][i] = 0;
  643.  
  644.     EraseRect(tWindow->RPort, ScrInfo->FieldInLeft, ScrInfo->FieldInTop,
  645.          ScrInfo->FieldInLeft + ScrInfo->FieldInWidth - 1,
  646.          ScrInfo->FieldInTop + ScrInfo->FieldInHeight - 1);
  647.  
  648.     DBUG_VOID_RETURN;
  649. }
  650.  
  651. /*
  652. **
  653. **  NewPiece()
  654. **
  655. **  Set up and display a new piece
  656. **
  657. */
  658. BOOL NewPiece(struct PieceRot *p, int x, int y)
  659. {
  660.     BOOL loser=FALSE;
  661.     int i,j;
  662.  
  663.     DBUG_ENTER("NewPiece");
  664.  
  665.     Piece = p;
  666.     Px = x;
  667.     Py = y;
  668.  
  669.  
  670.     for (i=0; i<Piece->width && !loser; i++)
  671.     for (j=0; j<Piece->height && !loser; j++)
  672.         if (Piece->map[j*Piece->width+i] && Field[Px+i][Py+j]) loser=TRUE;
  673.  
  674.     BltBitMapRastPort(&Piece->BitMap,0,0, tWindow->RPort,
  675.     ScrInfo->FieldInLeft + Px * ScrInfo->xTimes,
  676.     ScrInfo->FieldInTop + Py * ScrInfo->yTimes,
  677.     Piece->width * ScrInfo->xTimes, Piece->height * ScrInfo->yTimes, 0x60);
  678.  
  679.     PieceCount[p->type]++;
  680.     if (pWindow)
  681.     DispPCount(ScrInfo, pWindow, Pieces[p->type], PieceCount[p->type]);
  682.  
  683.     DBUG_PRINT("NP",("List drawn, loser = %d",loser));
  684.  
  685.     DBUG_RETURN(loser);
  686. }
  687.  
  688. /*
  689. **
  690. **  PlacePiece()
  691. **
  692. **  Add the piece to the playfield
  693. **
  694. */
  695.  
  696. void PlacePiece(void) {
  697.  
  698.     int i,j,k;
  699.     int numlines;
  700.     int lines[4];
  701.     int add2score = 1;
  702.  
  703.     DBUG_ENTER("PlacePiece");
  704.  
  705.     /*    Add the piece to the playfield array  */
  706.     for (i=0; i<Piece->height; i++)
  707.     for (j=0; j<Piece->width; j++)
  708.         if (Piece->map[i*Piece->width+j]) Field[Px+j][Py+i] = 1;
  709.  
  710.     /*    Increment the score  */
  711.     Score++;
  712.  
  713.     /*    And check to see if any lines are complete  */
  714.     for (j=Py+Piece->height-1, numlines=0; j>=Py; j--) {
  715.     for (i=0; i<FWIDTH && Field[i][j]; i++);
  716.     if (i==FWIDTH) {
  717.         lines[numlines]=j;
  718.         DBUG_PRINT("PP",("Line %d filled.", lines[numlines]));
  719.         numlines++;
  720.     }
  721.     }
  722.  
  723.     /*    If lines have been completed  */
  724.     if (numlines) {
  725.  
  726.     /*  Do the graphics ...  */
  727.     for (i=0; i<numlines; i++) {
  728.         DBUG_PRINT("PP",("Reversing line %d", lines[i]));
  729.         BltBitMapRastPort(tWindow->RPort->BitMap,0,0,tWindow->RPort,
  730.             ScrInfo->FieldInLeft,
  731.             ScrInfo->FieldInTop + lines[i]*ScrInfo->yTimes,
  732.             ScrInfo->xTimes * FWIDTH, ScrInfo->yTimes, 0x50);
  733.     }
  734.  
  735.     /*  The array ... */
  736.     for (i=numlines-1; i>=0; i--) {
  737.         DBUG_PRINT("PP",("Cleaning array for line %d", lines[i]));
  738.         for (k=lines[i]; k>0; k--)
  739.         for (j=0; j<FWIDTH; j++)
  740.             Field[j][k]=Field[j][k-1];
  741.         for (j=0; j<FWIDTH; j++)
  742.         Field[i][0] = 0;
  743.     }
  744.  
  745.     /*  More graphics ... */
  746.     for (i=numlines-1; i>=0; i--) {
  747.         DBUG_PRINT("PP",("Scrolling over line %d", lines[i]));
  748.         for (j=0; j<ScrInfo->yTimes; j++)
  749.         ScrollRaster(tWindow->RPort, 0, -1,
  750.             ScrInfo->FieldInLeft, ScrInfo->FieldInTop,
  751.             ScrInfo->FieldInLeft+FWIDTH*ScrInfo->xTimes-1,
  752.             ScrInfo->FieldInTop+lines[i]*ScrInfo->yTimes+j);
  753.     }
  754.  
  755.     /*  And increment the score properly  */
  756.     for (i=0; i<numlines; i++) add2score *=10;
  757.     Score += add2score;
  758.     Lines += numlines;
  759.     if ( (Lines>=(Level-StartLev+1)*Lin2Inc) && (Level<CapLev-1)) Level++;
  760.     }
  761.  
  762.     UpdateScores(tWindow, ScrInfo, Level, Score, Lines);
  763.  
  764.     DBUG_VOID_RETURN;
  765. }
  766.  
  767. /*
  768. **
  769. **  MovePiece()
  770. **
  771. **  Move the Bob to the new location, and return whether it's hitting
  772. **
  773. */
  774.  
  775. BOOL MovePiece(enum direction dir)
  776. {
  777.     BOOL legal = TRUE, hitting = FALSE;
  778.     int i, j;
  779.  
  780.     DBUG_ENTER("MovePiece");
  781.  
  782.     /*    Check the legality of the move    */
  783.     switch (dir) {
  784.  
  785.     case down:
  786.     if (Py + Piece->height == FHEIGHT) legal=FALSE;
  787.     for (i=0; i < Piece->width && legal; i++)
  788.         for (j= Piece->height - 1; j >= 0; j--)
  789.         if (Piece->map[ j * Piece->width + i])  {
  790.             if (Py+j+1 >= FHEIGHT) legal=FALSE;
  791.             else if (Field[Px+i][Py+j+1]) legal=FALSE;
  792.             break;
  793.         }
  794.     break;
  795.  
  796.     case left:
  797.     if (Px == 0) legal=FALSE;
  798.     for (j=0; j < Piece->height && legal; j++)
  799.         for (i=0; i < Piece->width; i++)
  800.         if (Piece->map[ j * Piece->width + i]) {
  801.             if (Px+i <= 0) legal=FALSE;
  802.             else if (Field[Px+i-1][Py+j]) legal=FALSE;
  803.             break;
  804.         }
  805.     break;
  806.  
  807.     case right:
  808.     if (Px + Piece->width == FWIDTH) legal=FALSE;
  809.     for (j=0; j < Piece->height && legal; j++)
  810.         for (i = Piece->width - 1; i >= 0; i--)
  811.         if (Piece->map[ j * Piece->width + i]) {
  812.             if (Px+i+1 >= FHEIGHT) legal=FALSE;
  813.             else if (Field[Px+i+1][Py+j]) legal=FALSE;
  814.             break;
  815.         }
  816.     break;
  817.  
  818.     default:
  819.     break;
  820.  
  821.     }
  822.  
  823.     if (legal) {
  824.  
  825.     /*  Remove the old image  */
  826.     BltBitMapRastPort(&Piece->BitMap,0,0,tWindow->RPort,
  827.         ScrInfo->FieldInLeft+ScrInfo->xTimes*Px,
  828.         ScrInfo->FieldInTop+ScrInfo->yTimes*Py,
  829.         Piece->width*ScrInfo->xTimes, Piece->height*ScrInfo->yTimes,
  830.         0x20);
  831.  
  832.     switch (dir) {
  833.         case down:    Py++; break;
  834.         case left:    Px--; break;
  835.         case right: Px++; break;
  836.         default:    break;
  837.     }
  838.  
  839.     /*  And display the new one  */
  840.     BltBitMapRastPort(&Piece->BitMap,0,0,tWindow->RPort,
  841.         ScrInfo->FieldInLeft+ScrInfo->xTimes*Px,
  842.         ScrInfo->FieldInTop+ScrInfo->yTimes*Py,
  843.         Piece->width*ScrInfo->xTimes, Piece->height*ScrInfo->yTimes,
  844.         0x60);
  845.  
  846.     }
  847.  
  848.     hitting = IsHitting(Piece, Px, Py);
  849.  
  850.     DBUG_PRINT("MP",("Piece Moved, hitting=%d",hitting));
  851.  
  852.     DBUG_RETURN(hitting);
  853. }
  854.  
  855. /*
  856. **
  857. **  PieceRot()
  858. **
  859. **  Rotate the piece 1/4 turn clockwise
  860. **
  861. */
  862. BOOL RotatePiece(void)
  863. {
  864.     struct PieceRot *np;
  865.     int nx, ny;
  866.     int i, j;
  867.     BOOL legal = TRUE, hitting = FALSE;
  868.  
  869.     DBUG_ENTER("RotatePiece");
  870.  
  871.     np = Piece->next;
  872.     nx = Px;
  873.     ny = Py;
  874.  
  875.     while (nx + np->width > FWIDTH) nx--;
  876.  
  877.     if (ny + np->height > FHEIGHT) legal = FALSE;
  878.     else for (i=0; i < np->width && legal; i++)
  879.     for (j = np->height - 1; j >= 0; j--)
  880.         if (np->map[j * np->width + i] && Field[nx+i][ny+j]) {
  881.         legal=FALSE;
  882.         break;
  883.         }
  884.  
  885.     if (legal) {
  886.     /*  Remove the old piece  */
  887.     BltBitMapRastPort(&Piece->BitMap,0,0,tWindow->RPort,
  888.         ScrInfo->FieldInLeft+ScrInfo->xTimes*Px,
  889.         ScrInfo->FieldInTop+ScrInfo->yTimes*Py,
  890.         Piece->width*ScrInfo->xTimes, Piece->height*ScrInfo->yTimes,
  891.         0x20);
  892.  
  893.     /*  Change some things    */
  894.     Px = nx;
  895.     Py = ny;
  896.     Piece = np;
  897.  
  898.     /*  And display the new piece  */
  899.     BltBitMapRastPort(&Piece->BitMap,0,0,tWindow->RPort,
  900.         ScrInfo->FieldInLeft+ScrInfo->xTimes*Px,
  901.         ScrInfo->FieldInTop+ScrInfo->yTimes*Py,
  902.         Piece->width*ScrInfo->xTimes, Piece->height*ScrInfo->yTimes,
  903.         0x60);
  904.  
  905.     }
  906.  
  907.     hitting = IsHitting(Piece, Px, Py);
  908.  
  909.     DBUG_RETURN(hitting);
  910. }
  911.  
  912. /*
  913. **
  914. **  ByeBye()
  915. **
  916. */
  917.  
  918. void ByeBye(int back)
  919. {
  920.     DBUG_ENTER("ByeBye");
  921.  
  922.     DBUG_PRINT("Bye",("Emergency Exit:  Code %d", back));
  923.  
  924.     exit (back);
  925.  
  926.     DBUG_VOID_RETURN;
  927. }
  928.  
  929. /*
  930. **
  931. **  GameOver()
  932. **
  933. **  Display the "Game Over" requester and ask if the user wants to play again.
  934. **
  935. */
  936. BOOL GameOver(void)
  937. {
  938.     struct EasyStruct es = {
  939.     sizeof(struct EasyStruct),
  940.     0,
  941.     "YacTris",
  942.     "\nGame Over\n\nFinal Score: %ld\nLines Cleared: %ld\n\nPlay Again?\n",
  943.     "Yes|No"
  944.     };
  945.  
  946.     int over;
  947.  
  948.     DBUG_ENTER("GameOver");
  949.  
  950.     over = !(EasyRequest(tWindow, &es, NULL, (APTR) Score, Lines));
  951.  
  952.     DBUG_RETURN(over);
  953. }
  954.  
  955. /*
  956. **
  957. **  ResetTet()
  958. **
  959. **  Reset everything for a new game.
  960. **
  961. */
  962. void ResetTet(void)
  963. {
  964.     int i;
  965.  
  966.     DBUG_ENTER("ResetTet");
  967.  
  968.     ClearPlayField();
  969.     Score = Lines = 0;
  970.     Level = StartLev;
  971.     UpdateScores(tWindow, ScrInfo, Level, Score, Lines);
  972.     for (i=0; i<NUM_TYPES; i++) PieceCount[i] = 0;
  973.     if (pWindow) for (i=0; i<NUM_TYPES; i++)
  974.     DispPCount(ScrInfo, pWindow, Pieces[i], 0);
  975.     NewPiece( PickPiece(), STARTX, STARTY);
  976.  
  977.     DBUG_VOID_RETURN;
  978. }
  979.  
  980. /*
  981. **  FillInTWindow
  982. **
  983. **  Recolor the proper blocks.
  984. **
  985. */
  986. void FillInTWindow(struct Window *tw, struct ScreenInfo *si)
  987. {
  988.     int i,j;
  989.     PLANEPTR tr;
  990.     struct TmpRas TR;
  991.     const UWORD fill = 0xffff;
  992.  
  993.     DBUG_ENTER("FillInTWindow");
  994.  
  995.     SetAfPt(tw->RPort, &fill, 0);
  996.  
  997.     for (i=0; i<FWIDTH; i++)
  998.     for (j=0; j<FHEIGHT; j++)
  999.         if (Field[i][j])
  1000.         BltBitMapRastPort(&Sqbm, 0, 0, tw->RPort,
  1001.             si->FieldInLeft + i*si->xTimes,
  1002.             si->FieldInTop + j*si->yTimes,
  1003.             si->xTimes, si->yTimes,
  1004.             0x60);
  1005.  
  1006.     DBUG_VOID_RETURN;
  1007. }
  1008.  
  1009.  
  1010. /*
  1011. **
  1012. **  IsHitting()
  1013. **
  1014. **  Returns TRUE if a piece is resting on a piece below it.
  1015. **
  1016. */
  1017. BOOL IsHitting(struct PieceRot *p, int x, int y)
  1018. {
  1019.     int i,j;
  1020.     BOOL hitting = FALSE;
  1021.  
  1022.     DBUG_ENTER("IsHitting");
  1023.  
  1024.     for (i=0; i<p->width && !hitting; i++)
  1025.     for (j=p->height-1; j>=0; j--)
  1026.         if (p->map[j*p->width+i]) {
  1027.         hitting = (BOOL)((y+j+1==FHEIGHT) || (Field[x+i][y+j+1]));
  1028.         break;
  1029.         }
  1030.  
  1031.     DBUG_RETURN(hitting);
  1032. }
  1033.  
  1034. /*
  1035. **
  1036. **  DoNewPubScreen
  1037. **
  1038. **  Open the YacTris window on a new screen.
  1039. **
  1040. */
  1041. void DoNewPubScreen(struct Screen *news)
  1042. {
  1043.     struct ScreenInfo *si = NULL;
  1044.     struct Window *tw = NULL;
  1045.     struct Window *pw = NULL;
  1046.     struct Menu *tm = NULL;
  1047.  
  1048.     BOOL success = FALSE;
  1049.  
  1050.     int i;
  1051.  
  1052.     DBUG_ENTER("OpenNewPubScreen");
  1053.  
  1054.     if (si = CreateScrInfo(news)) {
  1055.     if (tm = CreateMenus(tNewMenu, TAG_END)) {
  1056.         if (LayoutMenus(tm, si->vi, TAG_END)) {
  1057.         if (tw=OpenTWindow(si, tm)) {
  1058.             MakePieces(si);
  1059.             FillInTWindow(tw, si);
  1060.             if (ShowNext) {
  1061.             BltBitMapRastPort(&Next->BitMap, 0, 0,
  1062.                 tw->RPort, si->NPLeft, si->NPTop,
  1063.                 4*si->xTimes, 4*si->yTimes, 0xc0);
  1064.             } else {
  1065.             ClearMenuStrip(tw);
  1066.             ItemAddress(tm, FULLMENUNUM(1,0,NOSUB))->Flags
  1067.                 &= ~CHECKED;
  1068.             ResetMenuStrip(tw,tm);
  1069.             }
  1070.             if (pWindow) {
  1071.             if (pw=OpenPWindow(si, tw->UserPort)) {
  1072.                 for (i=0; i<NUM_TYPES; i++)
  1073.                 DispPCount(si, pw, Pieces[i], PieceCount[i]);
  1074.                 ClearMenuStrip(tw);
  1075.                 ItemAddress(tm, FULLMENUNUM(1,1,NOSUB))->Flags
  1076.                     |= CHECKED;
  1077.                 ResetMenuStrip(tw, tm);
  1078.             } else {
  1079.                 ClearMenuStrip(tw);
  1080.                 ItemAddress(tm, FULLMENUNUM(1,1,NOSUB))->Flags
  1081.                     &= ~CHECKED;
  1082.                 ResetMenuStrip(tw, tm);
  1083.             }
  1084.             } else {
  1085.             pw = NULL;
  1086.             ClearMenuStrip(tw);
  1087.             ItemAddress(tm, FULLMENUNUM(1,1,NOSUB))->Flags
  1088.                 &= ~CHECKED;
  1089.             ResetMenuStrip(tw, tm);
  1090.             }
  1091.  
  1092.             if (pWindow) ClosePWindow(pWindow);
  1093.             pWindow = pw;
  1094.  
  1095.             CloseTWindow(tWindow);
  1096.             tWindow = tw;
  1097.  
  1098.             FreeMenus(tMenus);
  1099.             tMenus = tm;
  1100.  
  1101.             UnlockPubScreen (NULL, ScrInfo->s);
  1102.             FreeScrInfo(ScrInfo);
  1103.             ScrInfo = si;
  1104.  
  1105.             tScreen = news;
  1106.  
  1107.             success = TRUE;
  1108.         }
  1109.         }
  1110.     }
  1111.     }
  1112.  
  1113.     if (!success) {
  1114.     if (pw) ClosePWindow(pw);
  1115.     if (tw) CloseTWindow(tw);
  1116.     if (tm) FreeMenus(tm);
  1117.     if (si) FreeScrInfo(si);
  1118.     }
  1119.  
  1120.     DBUG_VOID_RETURN;
  1121.  
  1122. }
  1123.  
  1124. /*
  1125. **
  1126. **  VerifyQuit
  1127. **
  1128. **  Check to be sure the user really wants to quit.
  1129. **
  1130. */
  1131. BOOL VerifyQuit(void)
  1132. {
  1133.     struct EasyStruct es = {
  1134.     sizeof(struct EasyStruct),
  1135.     0,
  1136.     "YacTris Request",
  1137.     "Final Score: %ld\nLines Cleared: %ld\n\nReally Quit?\n",
  1138.     "Yes|No"
  1139.     };
  1140.  
  1141.     int ret;
  1142.  
  1143.     DBUG_ENTER("VerifyQuit");
  1144.  
  1145.     ret = EasyRequest(tWindow, &es, NULL, (APTR) Score, Lines);
  1146.  
  1147.     DBUG_RETURN(ret);
  1148. }
  1149.  
  1150.